import React, { useCallback } from 'react';
import DataEdit from '../base/DataEdit';
import DataTable from '../base/DataTable';
import DataImport, { downLoadTemplateFile } from '../base/DataImport';
import IconFont from '../base/IconFont';
import { useReducer, useMemo, useRef } from 'react';
import { removeKeys, submitDatas } from '@/services/commCRUD';
import PageHeader from './PageHeader';
import { useModel, history } from 'umi';
import { Button, message, Space, Modal } from 'antd';
import _ from 'lodash';
import { convertStrToVal } from '@/utils/common';
import { format } from '@/utils/datetime';
import { ReloadOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
import KeepAlive from 'react-activation';
// 属性类型
type PropField = {
  /** 后台dao的名称 */
  daoName: string;
  /** 表格使用的column列表 */
  columns: API.Column[];
  /** 编辑使用的control列表 */
  controls: API.Control[];
  /** 表格每页显示的行数 */
  pageSize?: number;
  /** 编辑窗口的宽度 */
  editWidth?: number;
  /** 表格的初始排序 */
  initSorter?: API.OrderItem;
  /** 表格数据的查询条件 */
  seeks?: API.WhereCause[];
  /** 数据保存时使用的额外的值，比如当前用户{uid:15}*/
  extraVals?: Record<string, any>;
  /** 额外的按钮，比如初始化密码*/
  extraButtons?: JSX.Element;
  /** 主键列的名称，用于生成表格react.Key，以及保存数据，必须配置正确 */
  keyColName?: string;
  /** 是否可以多选*/
  multiSelect?: boolean;
  /** 编辑导入窗口显示的标题*/
  title?: string;
  /** 导入配置名称，按照这个名称生成后台的配置表，必须唯一 */
  importName?: string;
  /** 导入时使用的后台dao名称 */
  importDaoName?: string;
  /** 导入时区分一条数据的唯一键，用于导入模式InsertAndUpdate和UpdateOnly */
  importKeys?: string[];
  /** 导入模版的名称 */
  importTemplateName?: string;
  /** 导入使用的控件列表 */
  importControls?: API.Control[];
  /** 导入方式 */
  importMode?: API.ImportMode;
  /** 导入使用的参数，填写control的name */
  importParamNames?: string[];
  /** 导入使用的参数值， 比如当前用户{uid:15}*/
  importParamVals?: Record<string, any>;
  /** 是否开启复制另赠，默认为false*/
  copyAdd?: boolean;
  /** 是否开启重新计算，默认为false*/
  canRecompute?: boolean;
  /** 复制另赠时的默认值*/
  copyAddInitVals?: Record<string, any>;
  /** 快捷过滤，在页面工具条上添加过滤控件*/
  shortcutFilters?: API.ShortcutFilter;
  /** 是否把Shortcut作为外部值*/
  extraValsByShortcut?: boolean;
  /** 快捷改变*/
  onShortcutChange?: (vals: Record<string, any>) => Promise<void>;
  /** 表格选择改变时触发的回调 */
  onSelectChange?: (selKeys: React.Key[], selRows: object[]) => Promise<void>;
};
type StateField = {
  selRows?: Record<string, any>[];
  seeks?: API.WhereCause[];
  showEdit?: boolean;
  showImport?: boolean;
  editType?: 'add' | 'update' | 'copyAdd';
  shortcutVals?: Record<string, any>;
};
const CommonPage: React.FC<PropField> = (props) => {
  const [state, dispatch] = useReducer(
    (prevState: StateField, newState: StateField) => {
      return { ...prevState, ...newState };
    },
    {
      selRows: [],
      seeks: [],
      showEdit: false,
      showImport: false,
      editType: 'add',
      shortcutVals: {},
    },
  );
  const tableRef = useRef<API.TableAction>();
  const { permTypes } = useModel('sysInfo', (ret) => ({
    permTypes: ret.getCurPermTypes(),
  }));
  const canEdit = permTypes && permTypes.indexOf('2') !== -1;
  const canImport = permTypes && permTypes.indexOf('K') !== -1;
  const shortcutFilters = useMemo(() => {
    const valsChange = (vals: Record<string, any>) => {
      let wcs: API.WhereCause[];
      const shortcutVals: Record<string, any> = {};
      if (props.shortcutFilters?.convert) {
        wcs = props.shortcutFilters?.convert(vals);
      } else {
        wcs = [{ WhereItems: [], RelationSign: 'AND' }];
        props.shortcutFilters?.controls.forEach((c) => {
          const val = convertStrToVal(c, vals[c.name]);
          shortcutVals[c.name] = val;
          if (c.dataType === 'date' || c.dataType === 'datetime') {
            vals[c.name] = format(val, 'yyyy-MM-dd');
          }
          if (vals[c.name]) {
            wcs[0].WhereItems.push({
              FieldName: c.name,
              Operator: '=',
              FieldValues: '' + vals[c.name],
            });
          }
        });
      }
      if (props.onShortcutChange) {
        props.onShortcutChange(vals);
      }
      dispatch({ seeks: wcs, shortcutVals });
    };
    if (!_.isEmpty(props.shortcutFilters?.controls)) {
      const initVals: Record<string, any> = {};
      props.shortcutFilters?.controls.forEach((c) => {
        initVals[c.name] = c.initValue;
      });
      if (props.shortcutFilters?.convert) {
        valsChange(initVals);
      }
      return (
        <DataEdit
          key="shortcut"
          controls={props.shortcutFilters!.controls}
          showType="inner"
          layout="inline"
          renderButtons={false}
          grid={false}
          width={300}
          autoFocusFirstInput={false}
          initVals={initVals}
          onValuesChange={(_cVals, vals) => valsChange(vals)}
        />
      );
    }
    return;
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [props.shortcutFilters?.controls]);
  const buttons = useMemo(() => {
    if (!permTypes) {
      return;
    }
    const reCompute = () => {
      if (!tableRef.current) {
        return;
      }
      if (_.isEmpty(tableRef.current.selKeys)) {
        message.info('请选择要重新计算的行');
        return;
      }
      const keys = tableRef.current!.selKeys!;
      const selRows: Record<string, any>[] = [];
      for (let i = 0; i < keys.length; i++) {
        const rowdata = tableRef.current!.rowDatas?.find(
          (row) => row[props.keyColName!] === keys[i],
        );
        selRows.push(rowdata!);
      }
      Modal.confirm({
        title: '提示',
        icon: <ExclamationCircleOutlined />,
        content: '您确定要重新计算选中的行吗？',
        onOk: () => {
          submitDatas(props.daoName, [], selRows as object, [])
            .then(function () {
              message.success(`重新计算成功`);
            })
            .catch(function (ex) {
              console.error('重新计算', props.daoName, '错误', ex);
            });
        },
        okText: '确认',
        cancelText: '取消',
      });
    };
    const delData = () => {
      if (!tableRef.current) {
        return;
      }
      if (_.isEmpty(tableRef.current.selKeys)) {
        return;
      }
      Modal.confirm({
        title: '提示',
        icon: <ExclamationCircleOutlined />,
        content: '您确定要删除选中的行吗？',
        onOk: () => {
          const keys = tableRef.current!.selKeys!;
          removeKeys(props.daoName, keys)
            .then(function (data) {
              const count = data as number;
              if (count >= 1) {
                if (tableRef.current) {
                  tableRef.current.reload();
                }
                message.success(`${props.title}删除成功`);
              }
            })
            .catch(function (ex) {
              console.error('删除', props.daoName, '错误', ex);
            });
        },
        okText: '确认',
        cancelText: '取消',
      });
    };
    const butts: JSX.Element[] = [];
    const openEdit = (type: 'add' | 'update' | 'copyAdd') => {
      if (!tableRef.current) {
        return;
      }
      if (type !== 'add') {
        if (_.isEmpty(tableRef.current.selKeys)) {
          message.warn('请选择要修改的数据行');
          return;
        }
      }
      dispatch({ editType: type, showEdit: true });
    };
    if (shortcutFilters !== undefined) {
      butts.push(shortcutFilters);
    }
    if (canEdit) {
      butts.push(
        <Button key="add" onClick={() => openEdit('add')}>
          <IconFont type="icon-xinzeng" />
          新增
        </Button>,
      );
      butts.push(
        <Button key="update" onClick={() => openEdit('update')}>
          <IconFont type="icon-xiugai" />
          修改
        </Button>,
      );
      if (props.copyAdd) {
        butts.push(
          <Button key="copyAdd" onClick={() => openEdit('copyAdd')}>
            <IconFont type="icon-fuzhi" />
            复制另增
          </Button>,
        );
      }
      butts.push(
        <Button key="del" onClick={() => delData()}>
          <IconFont type="icon-shanchu" />
          删除
        </Button>,
      );
      if (props.canRecompute) {
        butts.push(
          <Button key="recomp" onClick={() => reCompute()}>
            <ReloadOutlined style={{ color: 'red' }} />
            重新计算
          </Button>,
        );
      }
      butts.push(props.extraButtons!);
    }
    if (canImport) {
      butts.push(
        <Button key="down" onClick={() => downLoadTemplateFile(props.importTemplateName)}>
          <IconFont type="icon-xiazaimoban" />
          下载导入模版
        </Button>,
      );
      butts.push(
        <Button key="import" onClick={() => dispatch({ showImport: true })}>
          <IconFont type="icon-shujudaoru" />
          导入
        </Button>,
      );
    }
    butts.push(
      <Button
        key="refresh"
        onClick={() => {
          if (!_.isEmpty(tableRef.current)) {
            tableRef.current?.reload();
          }
        }}
      >
        <ReloadOutlined style={{ color: 'red' }} /> 刷新
      </Button>,
    );
    return butts;
  }, [
    permTypes,
    shortcutFilters,
    canEdit,
    canImport,
    props.keyColName,
    props.daoName,
    props.title,
    props.copyAdd,
    props.canRecompute,
    props.extraButtons,
    props.importTemplateName,
  ]);
  const getInitVals = useCallback(() => {
    if (_.isEmpty(tableRef.current) || _.isEmpty(tableRef.current!.selKeys)) {
      return {};
    }
    let vals: Record<string, any> = {};
    const key = tableRef.current!.selKeys![0];
    const selRows = tableRef.current!.rowDatas?.find((row) => row[props.keyColName!] === key);
    if (state.editType === 'update') {
      vals = selRows!;
    } else if (state.editType === 'copyAdd') {
      if (_.isEmpty(props.keyColName)) {
        message.error('copyAdd方式必须指定keyColName');
      } else {
        vals = { ...selRows!, [props.keyColName!]: undefined, ...props.copyAddInitVals };
      }
    }
    return vals;
  }, [props.copyAddInitVals, props.keyColName, state.editType]);
  const seeks: API.WhereCause[] = useMemo(() => {
    const shortcutInits = () => {
      if (props.shortcutFilters?.convert) {
        if (!_.isEmpty(state.seeks)) {
          return state.seeks!;
        }
      }
      const wcs: API.WhereCause[] = [{ WhereItems: [], RelationSign: 'AND' }];
      if (!props.shortcutFilters?.convert) {
        props.shortcutFilters?.controls.forEach((c) => {
          let val = convertStrToVal(c, c.initValue);
          if (c.dataType === 'date' || c.dataType === 'datetime') {
            val = format(val, 'yyyy-MM-dd');
          }
          if (val) {
            wcs[0].WhereItems.push({
              FieldName: c.name,
              Operator: '=',
              FieldValues: '' + val,
            });
          }
        });
      }
      if (props.seeks && props.seeks.length > 0) {
        wcs.push(...props.seeks);
      }
      return wcs;
    };
    return shortcutInits();
  }, [props.shortcutFilters?.convert, props.shortcutFilters?.controls, props.seeks, state.seeks]);
  const path = history.location.pathname;
  let extraVals = props.extraVals;
  if (props.extraValsByShortcut) {
    extraVals = { ...extraVals, ...state.shortcutVals };
  }
  return (
    <PageHeader>
      <Space key="toolbar" style={{ marginTop: -10, marginBottom: 10 }}>
        {buttons}
      </Space>
      <KeepAlive key={path} when={true} name={path} id={path} saveScrollPosition={true}>
        <DataTable
          key="table"
          daoName={props.daoName}
          columns={props.columns}
          controls={props.controls}
          pageSize={props.pageSize!}
          keyColName={props.keyColName}
          initSorter={props.initSorter}
          seeks={seeks}
          actionRef={tableRef}
          title={props.title}
          multiSelect={props.multiSelect}
          onSelectChange={async (keys, rows) => {
            dispatch({ selRows: rows });
            if (props.onSelectChange) {
              props.onSelectChange(keys, rows);
            }
          }}
        />
      </KeepAlive>
      {canEdit && state.showEdit ? (
        <DataEdit
          key="edit"
          daoName={props.daoName}
          keyColName={props.keyColName}
          title={props.title}
          controls={props.controls}
          extraVals={extraVals}
          visible={state.showEdit}
          initVals={getInitVals()}
          onSumit={async () => {
            tableRef.current?.reload();
          }}
          onVisibleChange={(visible) => dispatch({ showEdit: visible })}
          renderButtons={(p) => {
            return [
              <Button type="default" key="rest" onClick={() => dispatch({ showEdit: false })}>
                取消
              </Button>,
              <Button type="primary" key="submit" onClick={() => p.form?.submit?.()}>
                保存
              </Button>,
            ];
          }}
        />
      ) : undefined}
      {canImport && state.showImport ? (
        <DataImport
          key="data_import"
          importName={props.importName!}
          importMode={props.importMode!}
          keys={props.importKeys!}
          daoName={props.importDaoName ? props.importDaoName : props.daoName}
          controls={props.importControls!}
          title={props.title!}
          visible={state.showImport}
          paramNames={props.importParamNames}
          paramVals={props.importParamVals}
          onVisibleChange={(show) => dispatch({ showImport: show })}
        />
      ) : undefined}
    </PageHeader>
  );
};
export default CommonPage;
CommonPage.defaultProps = {
  editWidth: 600,
  pageSize: 20,
  keyColName: 'ID',
  title: '',
  seeks: [],
  importTemplateName: '',
  copyAdd: false,
  multiSelect: false,
  extraValsByShortcut: false,
};
